`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/

/**
	@file UticaCPUExecuteBranchLogic.v
	@author Andrew D. Zonenberg
	@brief Branch / stall logic
 */
module UticaCPUExecuteBranchLogic(
	mem_mult, mem_multu, div_active,
	stall_for_mem_rs, stall_for_mem_rt,
	execute_uses_rs, execute_uses_rt,
	execute_rs_forwarded, execute_rt_forwarded,
	execute_mflo, execute_mfhi, execute_beq, execute_bne, execute_bgtz, execute_blez,
	execute_bgez, execute_bgezal, execute_bltz, execute_bltzal, execute_j, execute_jal,
	execute_jr, execute_jalr, execute_bubble,
	stall, execute_jumping, execute_cachemiss
    );
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// IO declarations
	
	input wire mem_mult;
	input wire mem_multu;
	
	input wire div_active;
	
	input wire stall_for_mem_rs;
	input wire stall_for_mem_rt;
	
	input wire execute_uses_rs;
	input wire execute_uses_rt;
	
	input wire[31:0] execute_rs_forwarded;
	input wire[31:0] execute_rt_forwarded;
	
	input wire execute_mflo;
	input wire execute_mfhi;
	input wire execute_beq;
	input wire execute_bne;
	input wire execute_bgtz;
	input wire execute_blez;
	input wire execute_bgez;
	input wire execute_bgezal;
	input wire execute_bltz;
	input wire execute_bltzal;
	input wire execute_j;
	input wire execute_jal;
	input wire execute_jr;
	input wire execute_jalr;
	
	input wire execute_bubble;
	
	output wire stall;
	output wire execute_jumping;
	
	input wire execute_cachemiss;

	////////////////////////////////////////////////////////////////////////////////////////////////
	// Main stall/branch logic

	//Multiplication and division
	/*
		Multiply takes 4 cycles to complete.
		
		Multiply			Read
		fetch
		decode
		execute			fetch
		mem				decode
		writeback		execute
		postwb1			mem
		postwb2			writeback
		
		When executing a read from $hi/$lo, in order for the result to be written in time,
		the mult needs to be in wb/postwb1/postwb2 when we are executing.
		
		Fetch and decode during our execute cannot interfere with us (since the mult happens
		after us) and execute is impossible. As a result, the only time we might need to stall is
		if we execute while the multiply is in the mem stage.
	 */
	 
	wire stall_for_mult;
	assign stall_for_mult = (mem_mult | mem_multu) & (execute_mflo | execute_mfhi);
	
	wire stall_for_div;
	assign stall_for_div = div_active & (execute_mflo | execute_mfhi);
	
	assign stall = stall_for_mult | stall_for_div | 
			(stall_for_mem_rs & !execute_bubble & execute_uses_rs) |			//No need to stall if instruction got bubbled out
			(stall_for_mem_rt & !execute_bubble & execute_uses_rt) |			//or if we just don't need the value
			execute_cachemiss;															//Stall in case of D-side cache miss
	
	//Decide if we're jumping or not
	//Note that if we're stalling for a memory read we have to not take the branch
	//since we're going to get bubbled
	wire execute_beq_active;
	assign execute_beq_active =
			execute_beq &&
			(execute_rs_forwarded == execute_rt_forwarded) &&
			!stall;
	wire execute_bne_active;
	assign execute_bne_active =
			execute_bne &&
			(execute_rs_forwarded != execute_rt_forwarded) &&
			!stall;
	wire execute_bgtz_active;
	assign execute_bgtz_active =
			execute_bgtz &&
			$signed(execute_rs_forwarded) > 0 &&
			!stall;	
	wire execute_blez_active;
	assign execute_blez_active =
			execute_blez &&
			$signed(execute_rs_forwarded) <= 0 &&
			!stall;
	wire execute_bgez_active;										//bgez and bgezal have same condition
	assign execute_bgez_active =
			(execute_bgez | execute_bgezal) &&
			$signed(execute_rs_forwarded) >= 0 &&
			!stall;	
	wire execute_bltz_active;										//bltz and bltzal have same condition
	assign execute_bltz_active =
			(execute_bltz | execute_bltzal) &&
			$signed(execute_rs_forwarded) < 0 &&
			!stall;
	
	assign execute_jumping = 
		execute_j | execute_jal |
		execute_jr | execute_jalr |
		execute_beq_active |
		execute_bne_active |
		execute_bgtz_active |
		execute_blez_active |
		execute_bgez_active |
		execute_bltz_active;

endmodule
